package common

import (
	"context"
	"errors"
	"fmt"
	"os/exec"
	"syscall"
	"time"

	"github.com/sirupsen/logrus"
)

type SHELL string

const (
	SH   SHELL = "sh"
	BASH SHELL = "bash"
)

type CommandResult struct {
	Stdout string
	Stderr error
	Code   int
	Err    error
}

func RunCommand(shell SHELL, cmdStrSrc []string, timeout time.Duration) *CommandResult {
	ret := &CommandResult{}
	cmdStr := []string{string(shell), "-c"}
	cmdStr = append(cmdStr, cmdStrSrc...)
	logrus.Infof("RunCommand: %v", cmdStr)
	// fmt.Println(cmdStr)
	cmd := exec.Command(cmdStr[0], cmdStr[1:]...)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
	}
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	go func(ctx context.Context) {
		select {
		case <-ctx.Done():
			return
		case <-time.After(timeout):
			if cmd == nil || cmd.Process == nil {
				ret.Code = -1
				ret.Stdout = ""
				// ret.Stderr = "cmd is nil."
				ret.Stderr = errors.New("cmd is nil.")
				return
			}
			if err := syscall.Kill(-1*cmd.Process.Pid, syscall.SIGKILL); err != nil {
				fmt.Println(err)
			}
		}
	}(ctx)
	out, err := cmd.CombinedOutput()
	ret.Code = cmd.ProcessState.ExitCode()
	ret.Stdout = string(out)
	// ret.Stderr = fmt.Sprintf("%v", err)
	ret.Stderr = err
	logrus.Infof("RunCommand Result: %+v", *ret)
	return ret
}
